package com.hk.core.authentication.security.authentication.accesstoken;

import com.hk.commons.JsonResult;
import com.hk.core.authentication.api.TokenGenerator;
import com.hk.core.authentication.api.UserPrincipal;
import com.hk.core.web.Webs;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.web.authentication.AuthenticationConverter;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.Objects;

@Slf4j
@Getter
public class AccessTokenAuthenticationFilter extends OncePerRequestFilter {

    private final SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
            .getContextHolderStrategy();

    private final TokenRequestMatcher requestMatcher;

    private final AuthenticationConverter authenticationConverter;

    private final TokenGenerator tokenGenerator;

    public AccessTokenAuthenticationFilter(String header, String tokenParameter, String cookieName, TokenGenerator tokenGenerator) {
        this(header, tokenParameter, cookieName, null, tokenGenerator);
    }

    public AccessTokenAuthenticationFilter(String header, String tokenParameter, String cookieName, Class<? extends UserPrincipal> principalClass,
                                           TokenGenerator tokenGenerator) {
        this.requestMatcher = new TokenRequestMatcher(header, tokenParameter, cookieName);
        this.tokenGenerator = tokenGenerator;
        var accessTokenAuthenticationConverter = new AccessTokenAuthenticationConverter(this.requestMatcher, this.tokenGenerator);
        if (Objects.nonNull(principalClass)) {
            accessTokenAuthenticationConverter.setPrincipalClass(principalClass);
        }
        this.authenticationConverter = accessTokenAuthenticationConverter;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        if (requestMatcher.matches(request)) {
            try {
                Authentication authentication = authenticationConverter.convert(request);
                SecurityContext context = securityContextHolderStrategy.createEmptyContext();
                context.setAuthentication(authentication);
                this.securityContextHolderStrategy.setContext(context);
            } catch (Exception e) {
                log.warn(e.getMessage(), e);
                //当有token，且token 解析失败后，直接响应
                Webs.writeJson(response, HttpServletResponse.SC_OK, JsonResult.unauthorized(e.getMessage()));
                return;
            }
        }
        filterChain.doFilter(request, response);
    }
}
